import java.util.ArrayList;
import java.util.List;

/**
 * 树可以看成是一个连通且 无环的无向图。
 *
 * 给定往一棵n 个节点 (节点值1～n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n中间，且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges，edges[i] = [ai, bi]表示图中在 ai 和 bi 之间存在一条边。
 *
 * 请找出一条可以删去的边，删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案，则返回数组edges中最后出现的边。
 *
 * 示例 1：
 * 输入: edges = [[1,2], [1,3], [2,3]]
 * 输出: [2,3]
 *
 * 示例 2：
 * 输入: edges = [[1,2], [2,3], [3,4], [1,4], [1,5]]
 * 输出: [1,4]
 *
 * 提示:
 * n == edges.length
 * 3 <= n <= 1000
 * edges[i].length == 2
 * 1 <= ai< bi<= edges.length
 * ai != bi
 * edges 中无重复元素
 * 给定的图是连通的
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/redundant-connection
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class Q00684m {

    /**
     * 性能不高
     * @param edges
     * @return
     */
    public int[] findRedundantConnection(int[][] edges) {
        List<Integer>[] outgoings = new ArrayList[edges.length + 1];
        for (int[] edge : edges) {
            if (find(outgoings, new boolean[edges.length + 1], edge[0], edge[1])) return edge;
            if (outgoings[edge[0]] == null) outgoings[edge[0]] = new ArrayList<>();
            if (outgoings[edge[1]] == null) outgoings[edge[1]] = new ArrayList<>();
            outgoings[edge[0]].add(edge[1]);
            outgoings[edge[1]].add(edge[0]);
        }
        return null;
    }

    private boolean find(List<Integer>[] outgoings, boolean[] visited, int from, int to) {
        if (outgoings[from] == null || visited[from]) return false;
        visited[from] = true;
        for (Integer target : outgoings[from]) {
            if (target == to || find(outgoings, visited, target, to)) return true;
        }
        return false;
    }

    /**
     * 并查集
     * @param edges
     * @return
     */
    public int[] findRedundantConnectionAns(int[][] edges) {
        int[] parent = new int[edges.length + 1];
        for (int i = 1; i < parent.length; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < edges.length; i++) {
            int[] edge = edges[i];
            int f1 = find(parent, edge[0]);
            int f2 = find(parent, edge[1]);
            if (f1 == f2) {
                return edge;
            }
            parent[f1] = f2;
        }
        return new int[0];
    }

    public int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }
}
